
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;

using Swaf;
using Swaf.BizObj;
using Swaf.BizRule;
using Swaf.Container;
using Swaf.Security;

using ICSharpCode.SharpZipLib.Zip.Compression;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using ICSharpCode.SharpZipLib.GZip;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Checksums;
using ICSharpCode.SharpZipLib.Core;

namespace eCom
{

	public class eComBizRules : Syrinx.BaseBizRules
	{
		public IBizObj getCheckOutWizard(IApplication app, IRuleContext context)
		{
			IBizObj wizard = app.bizObjMgr.create("eComCheckoutWizardOptions");
			IBizObjList precheckoutWizardSteps = context.RuleGroup.execute(context, "getPreCheckOutWizardSteps").CallResults as IBizObjList;
			if (precheckoutWizardSteps != null)
				wizard.put("preCheckoutSteps", precheckoutWizardSteps);
			return wizard;
		}

		public IBizObjList getPreCheckOutWizardSteps(IApplication app, IRuleContext context)
		{
			FlexiMap m = new FlexiMap();
			m.put("companyId", ActiveCompanyId);
			IBizObjList steps = app.appData.get("DA.eCom.GetPreCheckOutWizardSteps", m) as IBizObjList;
			foreach (IBizObj step in steps)
				step.put("viewName", App.resMgr.resolve("$CmpSetting(sitePath)$") + "/" + step.get("viewName"));
			return steps;
		}

		public void addPreCheckOutWizard(IApplication app, IRuleContext context, IBizObj step)
		{
			app.appData.put("DA.eCom.AddPreCheckOutWizardStep", step);
		}

		public void deletePreCheckOutWizard(IApplication app, IRuleContext context, IBizObj step)
		{
			app.appData.put("DA.eCom.DeletePreCheckOutWizardStep", step);
		}

		protected static string[] s_articleFieldsToCopy =
			{"id","baseTitle", "translatedtitles", "baseSummary", "translatedSummaries", "mediaCacheName"};
		public IBizObjList getSalesOrderWizardProducts(IApplication app, IRuleContext context, Swaf.BGuid.Guid salesOrderId)
		{
			bool salesOrderHasMembershipProduct = false;
			IBizObjList WizardList = app.bizObjMgr.createList("eComCheckoutWizardStep");
			Dictionary<string, IBizObj> stepArticles = new Dictionary<string, IBizObj>();
			int insertNewUserStepPosition = 1;

			//Create a wizard step for the initial checkout page.
			IBizObj initWiz = WizardList.insertNew();
			initWiz.put("completeOption", WizStepOptions.mustCompleteBeforeMoveForward);
			IBizObj article = app.ruleMgr.execute(context, "getArticleDetail", "InitialCheckoutWizard", false, DetailLevel.basicDetails, false, true, null).CallResults as IBizObj;
			if (article != null)
				foreach (string fname in s_articleFieldsToCopy)
					initWiz.put(fname, article.get(fname));


			bool hasNonZeroTotal = false;
			FlexiMap m = new FlexiMap();
			m.put("orderId", salesOrderId);
			IBizObjList salesOrderItems = app.appData.get("DA.eCom.GetSalesOrderItemsWithProductDetails", m) as IBizObjList;
			foreach (IBizObj orderItem in salesOrderItems)
				if ((decimal)orderItem.get("total") > 0M)
				{
					hasNonZeroTotal = true;
					break;
				}
			

			//If the company has payment terms defined, we will add a step for the user to provide
			//payment info.
			if ((bool)ActiveCompany.get("settings.hasPaymentTerms") && hasNonZeroTotal)
			{
				IBizObj paymentWiz = WizardList.insertNew();
				paymentWiz.put("completeOption", WizStepOptions.mustCompleteBeforeMoveForward);
				paymentWiz.put("viewName", App.resMgr.resolve("$CmpSetting(sitePath)$/std/PaymentInfo.aspx"));
				article = app.ruleMgr.execute(context, "getArticleDetail", "PaymentInfoWizard", false, DetailLevel.basicDetails, false, true, null).CallResults as IBizObj;
				if (article != null)
					foreach (string fname in s_articleFieldsToCopy)
						paymentWiz.put(fname, article.get(fname));
				insertNewUserStepPosition++;
			}

			bool showWizStepForUserMembershipProducts = true;
			if (ActiveCompany.get("settings.defaultCreateNewUser").ToString().CompareTo("createCalculated") == 0)
				showWizStepForUserMembershipProducts = false;

			foreach (IBizObj orderItem in salesOrderItems)
			{
				if (!Cmn.IsEmpty((string)orderItem.get("product.checkoutWizard")))
				{
					int q = (int)orderItem.get("quantity");
					for (int c = 0; c < q; c++)
					{
						string productPartId = orderItem.get("product.id").ToString();
						bool isUserMembership = productPartId.ToLower().StartsWith("um");
						if (!isUserMembership || (isUserMembership && showWizStepForUserMembershipProducts))
						{
							IBizObj wiz = WizardList.insertNew();
							wiz.put("product.partId", orderItem.get("product.partId"));
							wiz.put("product.id", orderItem.get("product.id"));
							wiz.put("salesOrderItemId", orderItem.get("id"));
							wiz.put("orderItemCombinedPartId", orderItem.get("calculatedProductPartId"));
							wiz.put("completeOption", WizStepOptions.mustCompleteBeforeMoveForward);
							wiz.put("indexInQuantity", c);
							string wizViewName = (string)orderItem.get("product.checkoutWizard");
							wiz.put("viewName", App.resMgr.resolve("$CmpSetting(sitePath)$") + wizViewName);
							if (((string)wiz.get("product.partId")).ToLower().StartsWith("um"))
								salesOrderHasMembershipProduct = true;

							if (!stepArticles.TryGetValue(wizViewName, out article))
								stepArticles[wizViewName] = article =
									app.ruleMgr.execute(context, "getArticleDetail", wizViewName, false, DetailLevel.basicDetails, false, true, null).CallResults as IBizObj;
							if (article != null)
								foreach (string fname in s_articleFieldsToCopy)
									wiz.put(fname, article.get(fname));
						}
					}
				}
			}
			if (!(bool)CurrentUser.get("authenticated") && !salesOrderHasMembershipProduct && showWizStepForUserMembershipProducts)
			{
				string defaultMembershipPartId = ActiveCompany.get("settings.defaultUserMembershipProductPartId") as string;
				if (!Cmn.IsEmpty(defaultMembershipPartId))
				{
					IResults rc = context.RuleGroup.execute(context, "getProductDetailsFromPartId", defaultMembershipPartId);
					IBizObj defaultMembership = rc.CallResults as IBizObj;
					if (defaultMembership != null)
					{
						IBizObj wiz = app.bizObjMgr.create("eComCheckoutWizardStep");
						wiz.put("product.partId", defaultMembership.get("partId"));
						wiz.put("product.id", defaultMembership.get("id"));
						string wizViewName = (string)defaultMembership.get("checkoutWizard");
						wiz.put("viewName", App.resMgr.resolve("$CmpSetting(sitePath)$") + wizViewName);
						wiz.put("completeOption", WizStepOptions.mustCompleteBeforeMoveForward);
						int i = wizViewName.LastIndexOfAny(new char[] { '/', '\\' });
						if (i != -1)
							wizViewName = wizViewName.Substring(i + 1);
						article = app.ruleMgr.execute(context, "getArticleDetail", wizViewName, false, DetailLevel.basicDetails, false, true, null).CallResults as IBizObj;
						if (article != null)
							foreach (string fname in s_articleFieldsToCopy)
								wiz.put(fname, article.get(fname));

						WizardList.Insert(insertNewUserStepPosition, wiz);
					}
					else
					{
						throw new eComException("There is a default user membership setup, but an exception occurred while getting it",rc.ExceptionInfo);
					}
				}
			}

			return WizardList;
		}

		public IBizObjList getAllCompanyProductArticlesForParent(IApplication app, IRuleContext context)
		{
			FlexiMap m = new FlexiMap();
			m.put("companyId", ActiveCompanyId);
			m.put("uniqueId", "eComSysStore");
			IBizObjList list = app.appData.get("DA.Articles.GetAllCompanyArticleIdTitle", m) as IBizObjList;
			return list;
		}
		
		public IBizObjList getEComProductTypes(IApplication app, IRuleContext context)
		{
			return app.appData["ArticleMetaTypeEComProductTypes"] as IBizObjList;
		}

		private static Swaf.BGuid.Guid[] s_madeupWizardStepIdsForDropDown = new Swaf.BGuid.Guid[]
			{
				new Swaf.BGuid.Guid("24C60059-2932-478f-8756-90EBB082A9A5"),
				new Swaf.BGuid.Guid("0F7EB53D-C952-44f1-9DBE-5A71E4CADB38"),
				new Swaf.BGuid.Guid("D180ECCB-A8FD-4b77-A6A3-FEBA3AE1E563"),
				new Swaf.BGuid.Guid("E99C519C-2A5D-4cf7-8DA9-28DB07158DC6"),
				new Swaf.BGuid.Guid("E8E874E9-E805-40ca-BBA0-FB8E14A5F836"),
				new Swaf.BGuid.Guid("D36887EF-D64B-4706-84F8-CF39132BBABA")
			};

		public IBizObjList getDefinedEComProductWizards(IApplication app, IRuleContext context)
		{
			IBizObjList productWizards = app.bizObjMgr.createList("eComCheckoutWizardStep");
			IBizObj noWizard = productWizards.insertNew();
			noWizard.put("baseTitle", "- No Checkout Wizard -");
			int idIndex = 0;
			noWizard.put("id", s_madeupWizardStepIdsForDropDown[idIndex++]);
			string baseDirectory = "CheckOutWizards";
			string sp = ActiveCompany.get("settings.sitePath").ToString();

			if (sp.Length > 0)
				baseDirectory = Cmn.pathCombine(sp.Substring(1), baseDirectory);

			string dirName = app.resMgr.resolve("$ConfigParam1$" + baseDirectory);

			if (dirName.StartsWith("file://"))
				dirName = dirName.Substring(7);
			if (Directory.Exists(dirName))
			{
				string[] files = Directory.GetFiles(dirName, "*.aspx");
				foreach(string file in files)
				{
					FileInfo f = new FileInfo(file);
					IBizObj Wizard = productWizards.insertNew();
					Wizard.put("id", s_madeupWizardStepIdsForDropDown[idIndex++]);
					Wizard.put("baseTitle", f.Name.Substring(0, f.Name.Length-5));
					Wizard.put("viewName", string.Format("/CheckOutWizards/{0}", f.Name));
				}
			}
			return productWizards;
		}
		
		
		public IBizObjList getEComStatusArticles(IApplication app, IRuleContext context)
		{
			try
			{
				INameAddressSupport info = new FlexiMap();
				info.put("parentId", "eComStatus");
				info.put("listDetailLevel", DetailLevel.idAndTitle);

				IBizObj criteria = null;
				IResults rc = app.ruleMgr.execute(context, "getArticles", info, criteria);
				IBizObjList stats = rc.CallResults as IBizObjList;
				if (stats != null)
					foreach (IBizObj stat in stats)
						if ("ecom_sysStatus_Open".CompareTo(stat.get("uniqueTitle")) == 0)
						{
							stats.Remove(stat);
							break;
						}
				return stats;
			}
			catch (Exception e)
			{
				throw new eComException("error executing getEComStatusArticles.", e);
			}

		}

		public void updateProduct(IApplication app, IRuleContext context, IBizObj product)
		{
			try
			{
				if (product == null)
					throw new BaseException("Must provide product when calling updateProduct");

				if (Cmn.IsEmpty(product.get("treeName")))
					product.put("treeName", "eComProd");
				if (product.get("companyId") == null)
					product.put("companyId", ActiveCompanyId);

				if (product.isNew)
					app.appData.put("DA.eCom.AddProduct", product);
				else
					app.appData.put("DA.eCom.UpdateProduct", product);
				context.RuleGroup.execute("updateArticle", product);
				if ("-Department".CompareTo(product.get("suggestedDisplayType")) == 0)
					context.RuleGroup.execute("refreshProductCatalogUniqueId");
			}
			catch (Exception e)
			{
				throw new eComException("error executing updateProduct.", e);
			}
		}

		public IBizObjList searchCompanyProductsWithParent(IApplication app, IRuleContext context, object pid, string searchString)
		{
			FlexiMap m = new FlexiMap();
			m.put("companyId", ActiveCompanyId);
			m.put("treeName", "eComProd");
			m.put("search", searchString);
			m.put("stripLeading", true);
			m.put("maxRows", 10);
			m.put("parentId", pid);
			IBizObjList list = app.appData.get("DA.Articles.SearchForArticlesFullTextIndex", m) as IBizObjList;
			return list;
		}
		public IBizObjList searchCompanyProducts(IApplication app, IRuleContext context, string searchString)
		{
			FlexiMap m = new FlexiMap();
			m.put("companyId", ActiveCompanyId);
			m.put("treeName", "eComProd");
			m.put("search", searchString);
			m.put("stripLeading", true);
			m.put("maxRows", 10);
			IBizObjList list = app.appData.get("DA.Articles.SearchForArticlesFullTextIndex", m) as IBizObjList;
			return list;
		}

		public IBizObjList searchCompanyProductsForParent(IApplication app, IRuleContext context, string searchString)
		{
			FlexiMap m = new FlexiMap();
			m.put("companyId", ActiveCompanyId);
			m.put("treeName", "eComProd");
			m.put("search", searchString);
			m.put("stripLeading", true);
			m.put("maxRows", 10);
            m.put("suggestedDisplayType", "-Department");
			IBizObjList list = app.appData.get("DA.Articles.SearchForCompanyArticleIdTitle", m) as IBizObjList;
			return list;
		}

		public IBizObjList getProductsForChildParentChoice(IApplication app, IRuleContext context)
		{
			FlexiMap m = new FlexiMap();
			m.put("companyId", ActiveCompanyId);
			m.put("treeName", "eComProd");
			IBizObjList list = (IBizObjList)app.appData.get("DA.Articles.GetAllCompanyArticleIdTitle", m);
			list.Insert(0, (IBizObj)app.appData.get("ArticleParentDropDown-Root"));
			return list;
		}

		public IBizObjList getProducts(IApplication app, IRuleContext context, INameAddressSupport info, IBizObj criteria)
		{
			try
			{
				info.put("includeECom", true);
				info.put("BizObjType", "eComProduct");
				if(Cmn.IsEmpty(info.get("objectTreeName")))
					info.put("objectTreeName", "eComProd");
				if (info.get("listDetailLevel") is string)
					info.put("listDetailLevel", (DetailLevel)Enum.Parse(typeof(DetailLevel), (string)info.get("listDetailLevel")));
				info.put("companyId", ActiveCompanyId);
				Swaf.BGuid.Guid parentId = info.get("parentId") as Swaf.BGuid.Guid;
				string parentName = info.get("parentId") as string;
				if (parentId == null)
					parentId = Swaf.BGuid.Guid.TryParse(parentName);
				if (parentId != null)
					info.put("parentId", parentId);
				string bizObjType = "eComProduct";
				int pageSize = 25;
				if (info.containsField("pageSize"))
					Int32.TryParse(info.get("pageSize").ToString(), out pageSize);
				bool useVirtual = false;
				if (Cmn.IsTrue(info.get("isPaging")))
					info.put("isPaging", useVirtual = true);

				IBizObjList products = new Swaf.BizObj.Virtual.SimpleVirtualBizObjList(bizObjType, "getChunkOfProducts", "getArticleCount", pageSize, new object[] { info, criteria });
				int i = products.numElements;//Will get the number of elements in list before returning..
				return products;
			}
			catch (Exception e)
			{
				throw new eComException("error executing getProducts.", e);
			}
		}

		public IBizObjList getChunkOfProducts(IApplication app, IRuleContext context, int pageSize, int currentPage, INameAddressSupport info, IBizObj criteria)
		{
			IResults rc = context.RuleGroup.execute(context, "getChunkOfArticles", pageSize, currentPage, info, criteria);
			if (rc.ExceptionInfo != null)
				throw rc.ExceptionInfo;
			IBizObjList products = rc.CallResults as IBizObjList;
			if (products != null)
			{
				IBizObjIterator i = app.bizObjMgr.getIterator("eComProductIterators");
				i.preIteration(context, ref products);
				foreach (IBizObj p in products)
					i.iterate(context, products, p);
				i.postIteration(context, ref products);
			}
			return products;
		}

		public IBizObj getProductDetailsFromPartId(IApplication app, IRuleContext context, string productPartId)
		{
			FlexiMap m = new FlexiMap();
			m.put("partId", productPartId);
			m.put("companyId", ActiveCompanyId);
			IBizObj product = app.appData.get("DA.eCom.GetProductDetailsFromPartId", m) as IBizObj;
			return product;
		}

		public IBizObj getProductDetails(IApplication app, IRuleContext context, object productId, bool withTranslation, DetailLevel detailLevel, bool incrementCount, bool stripLeading)
		{
			try
			{
				if (productId != null)
				{
                    IResults rc = context.RuleGroup.execute(context, "getArticleDetail", productId, withTranslation, detailLevel, incrementCount, stripLeading, "eComProduct");
					IBizObj product = rc.CallResults as IBizObj;
					if (product == null)
					{
						product = app.bizObjMgr.create("eComProduct");
						product.put("id", productId);
					}
					FlexiMap m = new FlexiMap();
					m.put("product", product);
					app.appData.get("DA.eCom.GetProductDetails", m);
					return product;
				}
				else
					throw new eComException("error executing getProductDetails. Product Id is null.");
			}
			catch (Exception e)
			{
				throw new eComException("error executing getProductDetails.", e);
			}
		}

		public void deleteProduct(IApplication app, IRuleContext context, Swaf.BGuid.Guid productId, bool deepDelete)
		{
			try
			{
				IResults rc = context.RuleGroup.execute(context, "getArticleDetail", productId, false, DetailLevel.idAndTitle, false, false, "eComProduct");
				IBizObj article = rc.CallResults as IBizObj;
				if (article != null)
				{
					string treeName = (string)article.get("treeName");
					if (treeName.StartsWith("Deleted"))
					{
						FlexiMap m = new FlexiMap();
						m.put("id", productId);
						app.appData.put("DA.eCom.DeleteProduct", m);
					}
					context.RuleGroup.execute("deleteArticle", productId, deepDelete);
				}
			}
			catch (Exception e)
			{
				throw new eComException("error executing deleteProduct.", e);
			}
		}

		public SalesOrderEditLevel getCurrentUserSalesOrderEditLevel(IApplication app, IRuleContext context, Swaf.BGuid.Guid orderId)
		{
			SalesOrderEditLevel level = SalesOrderEditLevel.none;
			IBizObj salesOrder = (IBizObj)context.RuleGroup.execute(context, "getSalesOrderDetails", orderId).CallResults;
			context.put("salesOrder", salesOrder);
			Privileges managePriv = CurrentPrincipal.getPrivilege("AppFunctions.ManageProducts");
			if (((IComparable)CurrentUser.get("id")).CompareTo(salesOrder.get("customer.id"))==0)
			{
				if ((Swaf.BGuid.Guid)salesOrder.get("status.id") == getArticleIdByUniqueTitle("ecom_sysStatus_CheckedOut"))
					level = SalesOrderEditLevel.full;
				else if ((Swaf.BGuid.Guid)salesOrder.get("status.id") == getArticleIdByUniqueTitle("ecom_sysStatus_InProgress"))
					level = SalesOrderEditLevel.basic;
			}
			return level;
		}

		public IBizObjList getSalesOrders(IApplication app, IRuleContext context, IBizObj criteria)
		{
			try
			{
				FlexiMap m = new FlexiMap();
				m.put("criteria", criteria);
				m.put("customer", CurrentUser);
				IBizObjList salesOrders = app.appData.get("DA.eCom.GetSalesOrders", m) as IBizObjList;
				return salesOrders;
			}
			catch (Exception e)
			{
				throw new eComException("error executing getSalesOrders.", e);
			}
		}

		public IBizObjList getUserSalesOrders(IApplication app, IRuleContext context, IBizObj criteria)
		{
			try
			{
				FlexiMap m = new FlexiMap();
				m.put("personalOnly", true);
				m.put("criteria", criteria);
				m.put("customer", CurrentUser);
				IBizObjList salesOrders = app.appData.get("DA.eCom.GetSalesOrders", m) as IBizObjList;
				return salesOrders;
			}
			catch (Exception e)
			{
				throw new eComException("error executing getSalesOrders.", e);
			}
		}

		public void clearCurrentSalesOrderId(IApplication app, IRuleContext context)
		{
			app.sessionData["CurrentOrderId"] = null;
		}

		public Swaf.BGuid.Guid getCurrentSalesOrderId(IApplication app, IRuleContext context)
		{
			Swaf.BGuid.Guid currentId = app.sessionData["CurrentOrderId"] as Swaf.BGuid.Guid;
			//if (currentId == null)
			//    app.sessionData["CurrentOrderId"] = currentId = new Swaf.BGuid.Guid();
			return currentId; 
		}

		public bool isProductOrChildInSalesOrder(IApplication app, IRuleContext context, Swaf.BGuid.Guid productId)
		{
			IMap m = new FlexiMap();
			m["parentId"] = productId;
			m["entireTree"] = true;
			m["includeSelf"] = false;
			m["listDetailLevel"] = DetailLevel.idOnly;
			IResults rc = context.RuleGroup.execute(context, "getProducts",  m, (IBizObj)null);
			IBizObjList products = rc.CallResults as IBizObjList;
			rc = context.RuleGroup.execute(context, "getCurrentSalesOrderId");
			Swaf.BGuid.Guid salesOrderId = rc.CallResults as Swaf.BGuid.Guid;
			rc = context.RuleGroup.execute(context, "getSalesOrderItems", salesOrderId);
			IBizObjList orderItems = rc.CallResults as IBizObjList;
			foreach (IBizObj orderItem in orderItems)
				foreach(IBizObj product in products)
					if(((IComparable)product.get("id")).CompareTo(orderItem.get("product.id")) == 0)
						return true;
			return false;
		}

		protected void setCurrentSalesOrderId(Swaf.BGuid.Guid currentOrderId)
		{
			App.sessionData["CurrentOrderId"] = currentOrderId;
		}

		public IBizObj getCurrentSalesOrderDetails(IApplication app, IRuleContext context)
		{
			IBizObj currentOrder = null;
			Swaf.BGuid.Guid orderId = getCurrentSalesOrderId(app, context);
			if (orderId != null)
				currentOrder = context.RuleGroup.execute(context, "getSalesOrderDetails", orderId).CallResults as IBizObj;
			return currentOrder;
		}

		public IBizObj getSalesOrderDetails(IApplication app, IRuleContext context, Swaf.BGuid.Guid orderId)
		{
			try
			{
				FlexiMap m = new FlexiMap();
				m.put("id", orderId);
				IBizObj salesOrder = app.appData.get("DA.eCom.GetSalesOrder", m) as IBizObj;
				if (salesOrder == null)
					throw new eComException("Cannot find order");

				if (salesOrder != null)
				{
					salesOrder.put("items", getSalesOrderItems(app, context, orderId));
					IResults rc = context.RuleGroup.execute(context, "getContactDetail", salesOrder.get("orderContact.id"));
					IBizObj contact = rc.CallResults as IBizObj;
					if (contact != null)
						salesOrder.put("orderContact", contact);
				}
				return salesOrder;
				
			}
			catch (Exception e)
			{
				throw new eComException("error executing getSalesOrderDetails.", e);
			}
		}

		public void setSalesOrderCustomer(IApplication app, IRuleContext context, Swaf.BGuid.Guid orderId)
		{
			FlexiMap m = new FlexiMap();
			m.put("orderId", orderId);
			m.put("customerId", CurrentUser.get("id"));
			m.put("companyId", CurrentUser.get("companyId"));

			app.appData.put("DA.eCom.SetSalesOrderCustomer", m);
		}

		public void updateSalesOrder(IApplication app, IRuleContext context, IBizObj order)
		{
			try
			{

				if (order != null)
				{
					DateTime utcNow = DateTime.Now.ToUniversalTime();
					app.Log.println(Swaf.Logging.LoggingLevels.High, "updateSalesOrder: order {0}", order.Xml);
					if (order.get("seqNumber").ToString().Length == 0)
						order.put("seqNumber", generateOrderNumber(app, context));
					if (order.isNew)
					{
						IResults rc = app.ruleMgr.execute(context, "getArticleDetail", "ecom_sysStatus_Open", false, DetailLevel.idOnly, false, true, null);
						if (rc.ExceptionInfo != null)
							throw new eComException("error executing updateSalesOrder.");
						if (rc.CallResults is IBizObj)
							order.put("status.id", ((IBizObj)rc.CallResults).get("id"));
						order.put("createdDate", utcNow);
					}
					else
						order.put("updatedDate", utcNow);

					if (DateTime.MinValue.CompareTo(order.get("lastItemChangeDate")) == 0)
						order.put("lastItemChangeDate", utcNow);
					app.appData.put(string.Format("DA.eCom.{0}", order.isNew ? "AddSalesOrder" : "UpdateSalesOrder"), order);
					if (!order.isNew && ((IBizObj)order.get("orderContact.defaultAddress")).isDirty())
						context.RuleGroup.execute("updateSalesOrderLastItemUpdatedTime", order.get("id"));
					order.isNew = false;
				}
				else
				{
					app.Log.println(Swaf.Logging.LoggingLevels.High, "updateSalesOrder: called with null for order param!");
				}
			}
			catch (Exception e)
			{
				throw new eComException("error executing updateSalesOrder.", e);
			}
		}

		public void userCanceledSalesOrder(IApplication app, IRuleContext context, Swaf.BGuid.Guid orderId)
		{
			IBizObj salesOrder = (IBizObj)context.RuleGroup.execute(context, "getSalesOrderDetails", orderId).CallResults;
			app.ruleMgr.execute("createStatusChangeHistory", salesOrder, getArticleIdByUniqueTitle("ecom_sysStatus_Cancelled"));
			context.RuleGroup.executeAsync("notifyObservers", null, "", new object[] { "ecomUserCanceledSalesOrder", salesOrder });
		}

		public IBizObj createNewUserShoppingCart(IApplication app, IRuleContext context, IBizObj orderItem)
		{
			app.Log.println(Swaf.Logging.LoggingLevels.High, "createNewUserShoppingCart: reusing order {0}", orderItem);
			IBizObj order = app.bizObjMgr.create("eComSalesOrder");
			order.put("id", new Swaf.BGuid.Guid());
			order.put("seqNumber", generateOrderNumber(app, context));
			IResults rc = context.RuleGroup.execute("updateSalesOrder", order);
			if (rc.ExceptionInfo != null)
				throw new eComException("error executing updateSalesOrder.", rc.ExceptionInfo);
			setCurrentSalesOrderId((Swaf.BGuid.Guid)order.get("id"));
			context.RuleGroup.executeAsync("notifyObservers", null, "", new object[]{"ecomShoppingCartCreated", new NameAddressStack(order, orderItem)});

			return order;
		}

		public void createStatusChangeHistory(IApplication app, IRuleContext context, IBizObj order, Swaf.BGuid.Guid statusId)
		{
			try
			{
				FlexiMap m = new FlexiMap();
				m.put("id", statusId);
				m.put("orderId", order.get("id"));
				m.put("date", DateTime.Now);
				app.appData.put("DA.eCom.CreateStatusChangeHistory",m);
				order.put("status.id", statusId);
				order.put("updatedDate", DateTime.Now.ToUniversalTime());
				app.appData.put("DA.eCom.UpdateSalesOrderStatus",order);
			}
			catch (Exception e)
			{
				throw new eComException("error executing createStatusChangeHistory.", e);
			}
		}
		public void deleteSalesOrder(IApplication app, IRuleContext context, Swaf.BGuid.Guid orderId)
		{
			try
			{
				if (orderId != null)
				{
					FlexiMap m = new FlexiMap();
					m.put("id", orderId);
					app.appData.put("DA.eCom.DeleteSalesOrder", m);
				}
			}
			catch (Exception e)
			{
				throw new eComException("error executing deleteSalesOrder.", e);
			}
		}
		public IBizObjList getSalesOrderItems(IApplication app, IRuleContext context, Swaf.BGuid.Guid orderId)
		{
			try
			{
				if (orderId == null)
					return app.bizObjMgr.createList("eComSalesOrderItem");
				FlexiMap m = new FlexiMap();
				m.put("orderId", orderId);
				m.put("defaultCacheName", ActiveCompany.get("settings.defaultMediaCache"));
				IBizObjList salesOrderItems = app.appData.get("DA.eCom.GetSalesOrderItems", m) as IBizObjList;
				return salesOrderItems;
			}
			catch (Exception e)
			{
				throw new eComException("error executing getSalesOrderItems.", e);
			}	
		}

		public void updateSalesOrderItemDetail(IApplication app, IRuleContext context, IBizObj orderItemDetail)
		{
			if (orderItemDetail.isNew)
				app.appData.put("DA.eCom.AddSalesOrderItemDetail", orderItemDetail);
			else
				app.appData.put("DA.eCom.UpdateSalesOrderItemDetail", orderItemDetail);
		}

		public IBizObj getSalesOrderItemDetail(IApplication app, IRuleContext context, Swaf.BGuid.Guid orderItemId, int itemIndex)
		{
			FlexiMap m = new FlexiMap();
			m.put("orderItemId", orderItemId);
			m.put("itemIndex", itemIndex);
			IBizObj orderItemDetail = app.appData.get("DA.eCom.GetSalesOrderItemDetail", m) as IBizObj;
			return orderItemDetail;
		}

		public IBizObjList getNewSalesOrder(IApplication app, IRuleContext context,Swaf.BGuid.Guid orderId)
		{
			try
			{
				
				IBizObj options = app.bizObjMgr.create("FilterSortOptions");
				IBizObj criteria = ((IBizObjList)options.get("filterOptions")).insertNew();
				criteria.put("field", "id");
				criteria.put("criteria","e");
				criteria.put("value",orderId);
				IResults rc = app.ruleMgr.execute("getSalesOrders", options);
				IBizObjList list = rc.CallResults as IBizObjList;
				if (list.numElements == 0)
				{
					IBizObj obj = list.insertNew();
					obj.put("id", new Swaf.BGuid.Guid());
					obj.put("seqNumber", generateOrderNumber(app, context));
					return list;
				}
				IBizObjList orderList = app.bizObjMgr.createList(list.objectType.Name);
				for (int i = 0; i < list.numElements; i++)
					if (Convert.ToDateTime(list[i].get("createdDate")) > DateTime.Now.ToUniversalTime().AddDays(-1)) 
					{
						orderList.Add(list[i]);
						break;
					}
				return list;
			}
			catch (Exception e)
			{
				throw new eComException("error executing getNewSalesOrder.",e);
			}
		}

		public string generateOrderNumber(IApplication app, IRuleContext context)
		{
			DateTime n = DateTime.Now.ToUniversalTime();
			DateTime fd = new DateTime(n.Year, 1, 1);
			TimeSpan sp = n - fd;
			
			//HACK - Need better way to get unique daily index then this.  But for Version 1, this will do.
			int dayIndex = 1;
			string fileName = app.resMgr.resolve("$SalesOrderIdFile$");
			if (fileName.StartsWith("file://", StringComparison.CurrentCultureIgnoreCase))
				fileName = fileName.Substring(7);
			try
			{
				lock (this.GetType())
				{
					if (File.Exists(fileName))
					{
						string c = File.ReadAllText(fileName);
						string[] cont = c.Split('|');
						string lastIndexDate = cont[0];
						if (n.ToShortDateString().CompareTo(lastIndexDate) == 0)
							dayIndex = int.Parse(cont[1]) + 1;
					}
					File.WriteAllText(fileName, n.ToShortDateString() + "|" + dayIndex);
				}
			}
			catch (Exception e)
			{
				throw new eComException(string.Format("generateOrderNumber unable to generate new order seq #.  Is {0} able to be written to?", fileName), e);
			}
			return "RS" + n.ToString("yy") + sp.Days.ToString("000") + dayIndex;
		}

		public void addOneQuantityOfProductToCurrentSalesOrder(IApplication app, IRuleContext context, Swaf.BGuid.Guid orderItemId)
		{
			app.Log.println(Swaf.Logging.LoggingLevels.High, "addOneQuantityOfProduct");
			app.Log.println(Swaf.Logging.LoggingLevels.High, "addOneQuantityOfProduct: {0}", orderItemId);
			Swaf.BGuid.Guid salesOrderId = context.RuleGroup.execute(context, "getCurrentSalesOrderId").CallResults as Swaf.BGuid.Guid;
			IBizObj orderItem = app.bizObjMgr.create("eComSalesOrderItem");
			orderItem.put("product.id", orderItemId);
			orderItem.put("orderId", salesOrderId);
			orderItem.put("quantity", 1);
			IResults rc = context.RuleGroup.execute(context, "updateSalesOrderItem", orderItem);
		}

		public List<Swaf.Gui.UserMessage> validateOrderItem(IApplication app, IRuleContext context, IBizObj orderItem)
		{
			List<Swaf.Gui.UserMessage> msgs = null;

			List<ValidationError> errors = orderItem.validate();
			if (!(errors == null || errors.Count == 0))
			{
				msgs = new List<Swaf.Gui.UserMessage>();
				foreach (ValidationError e in errors)
					msgs.Add(new Swaf.Gui.UserMessage("Error-InvalidParameter", e));
				return msgs;
			}

			int maxQuantity = (int)ActiveCompany.get("settings.eComMaxNumProducts");
			int itemQuantity = (int)orderItem.get("quantity");
			if (itemQuantity < 0 || (maxQuantity > 0 && itemQuantity > maxQuantity))
			{
				FlexiMap m = new FlexiMap();
				m.put("maxQuantity", maxQuantity);
				msgs = new List<Swaf.Gui.UserMessage>();
				msgs.Add(new Swaf.Gui.UserMessage("Error-OverUnderQuantity", m));
			}
			return msgs;

		}

		public IBizObj updateSalesOrderItem(IApplication app, IRuleContext context, IBizObj orderItem)
		{
			try
			{
				IResults rc = null;
				IBizObj order = null;
				Swaf.BGuid.Guid oid = orderItem.get("orderId") as Swaf.BGuid.Guid;
				if (oid != null)
				{
					FlexiMap m = new FlexiMap();
					m.put("id", oid);
					order = app.appData.get("DA.eCom.GetSalesOrderIdById", m) as IBizObj;
					app.Log.println(Swaf.Logging.LoggingLevels.High, "updateSalesOrderItem: reusing order {0}", oid);
				}

				//Create a new sales order when the user adds the first one to a new sales order.
				//This is the logic that allows us to offer "add to cart" without having to create a new
				//sales order right away.
				if (oid == null || order == null)
				{
					if ((order = context.RuleGroup.execute(context, "createNewUserShoppingCart", orderItem).CallResults as IBizObj) != null)
						oid = order.get("id") as Swaf.BGuid.Guid;
					app.Log.println(Swaf.Logging.LoggingLevels.High, "updateSalesOrderItem: creating new order {0}", oid);
				}

				if (oid != null && order != null)
				{
					orderItem.put("orderId", oid);

					string[] multiPartId = null;
					orderItem.put("calculatedProductPartId", orderItem.get("product.partId"));
					//This if statement helps when a product is not really in the database, but was created out of an option
					//on a real product.  this is needed to help track the partId for the "calculated" product.
					if ((bool)orderItem.get("product.isTempId"))
					{
						string calcId = orderItem.get("product.combinedId").ToString();
						if (!Cmn.IsEmpty(calcId))
						{
							multiPartId = calcId.Split('|');
							orderItem.put("product.id", new Swaf.BGuid.Guid(multiPartId[1]));
						}

					}

					if (!(context.get("priceIsSet") is bool && (bool)context.get("priceIsSet")))
					{
						Swaf.BGuid.Guid prodId = orderItem.get("product.id") as Swaf.BGuid.Guid;
						if (multiPartId != null)
							prodId = new Swaf.BGuid.Guid(multiPartId[0]);

						rc = app.ruleMgr.execute(context, "getProductDetails", prodId, false, Swaf.DetailLevel.basicDetails, false, true);
						if (rc.ExceptionInfo != null || rc.CallResults == null)
							throw new eComException("error processing updateSalesOrderItem. Invalid product id not found.", rc.ExceptionInfo);
						orderItem.put("price", ((IBizObj)rc.CallResults).get("sellPrice"));
					}

					bool isValid = context.RuleGroup.execute(context, "validateOrderItem", orderItem).CallResults == null;

					if (isValid)
					{
						if (orderItem.isNew)
						{
							if (!orderItem.isFieldSet("id"))
								orderItem.put("id", new Swaf.BGuid.Guid());
							app.appData.put("DA.eCom.AddSalesOrderItem", orderItem);
						}
						else
						{
							if ((int)orderItem.get("quantity") == 0)
								app.appData.put("DA.eCom.DeleteSalesOrderItem", orderItem);
							else
								app.appData.put("DA.eCom.UpdateSalesOrderItem", orderItem);
						}

						context.RuleGroup.execute("updateSalesOrderLastItemUpdatedTime", oid);
					}
				}
				else
					app.Log.println(Swaf.Logging.LoggingLevels.High, "updateSalesOrderItem: unable to get orderid {0}", oid);

				return orderItem;
			}
			catch (Exception e)
			{
				throw new eComException("error executing updateSalesOrderItem.", e);
			}
		}

		public void updateSalesOrderLastItemUpdatedTime(IApplication app, IRuleContext context, Swaf.BGuid.Guid orderId)
		{
			FlexiMap m = new FlexiMap();
			m["lastItemChangeDate"] = DateTime.UtcNow;
			m["id"] = orderId;
			app.appData.put("DA.eCom.UpdatesSalesOrderLastItemChange", m);
		}

		public void deleteSalesOrderItem(IApplication app, IRuleContext context, Swaf.BGuid.Guid orderItemId)
		{
			try
			{
				if (orderItemId != null)
					app.appData.put("DA.eCom.DeleteSalesOrderItem", orderItemId);
			}
			catch (Exception e)
			{
				throw new eComException("error executing deleteSalesOrderItem.", e);
			}
		}

		public void updateWarehouseItem(IApplication app, IRuleContext context, IBizObj warehouseItem)
		{
			try
			{
				if (warehouseItem != null)
					if (warehouseItem.isNew)
						app.appData.put("DA.eCom.AddWarehouseItem", warehouseItem);
					else
						app.appData.put("DA.eCom.UpdateWarehouseItem", warehouseItem);
				else
					throw new eComException("error executing updateWarehouseItem, product is required to update warehouse item");
			}
			catch (Exception e)
			{
				throw new eComException("error executing createWarehouseItem.", e);
			}
		}

		public void checkOutOrder(IApplication app, IRuleContext context, IBizObj salesOrder, Uri usersFirstUrlOnSite)
		{
			try
			{
				if (salesOrder == null)
					throw new eComException("Error-InvalidSalesOrder.");
				
				Swaf.BGuid.Guid orderId = salesOrder.get("id") as Swaf.BGuid.Guid;
				IResults rc = app.ruleMgr.execute(context, "getSalesOrderDetails", orderId);
				
				if(rc.ExceptionInfo!=null || rc.CallResults == null)
					throw new eComException("Error-InvalidSalesOrder");

				salesOrder = rc.CallResults as IBizObj;
				if (salesOrder != null)
				{
					salesOrder.put("items", getSalesOrderItems(app, context, orderId));
					rc = context.RuleGroup.execute(context, "getContactDetail", salesOrder.get("orderContact.id") as Swaf.BGuid.Guid);
					if (rc.CallResults is IBizObj)
						salesOrder.put("orderContact", rc.CallResults);
				}
			

				if (true.Equals(ActiveCompany.get("settings.postToUserEComAccount")))
				{

					//TODO: if  Account Exist ? userAccountId = user.get("id") : userAccountId = newGUID()
					// create usings eComAccountId as parentId
				}

				//TODO: create the account entry
				//IBizObj crentry = app.bizObjMgr.create("AccountEntry");
				//IBizObjList subEntries = app.bizObjMgr.createList("AccountEntry");
				//crentry.put("id",new Swaf.BGuid.Guid());
				//crentry.put("accountId",userAccountId);
				//crentry.put("date", DateTime.Now());
				//crentry.put("refNumber",eComOrder.get("seqNumber"));
				//crentry.put("amount",eComOrder.get("grandTotal"));
				//crentry.put("postedBy",CurrentUser.get("id"));
				//crentry.put("subEntries",subEntries);

				context.put("firstUrl", usersFirstUrlOnSite); //to be available to iterators.
				IBizObjList orderItems = salesOrder.get("items") as IBizObjList;
				IBizObjIterator i = app.bizObjMgr.getIterator("eComCheckoutOrderItemIterators");
				i.preIteration(context, ref orderItems);
				foreach (IBizObj oi in orderItems)
				{
					i.iterate(context, orderItems, oi);
					//IBizObj drentry = subEntries.insertNew();
					//drentry.put("id",new Swaf.BGuid.Guid());
					//drentry.put("amount",order.get("total"));
					//drentry.put("date",DateTime.Now());

					//Int32 qty = Convert.ToInt32(order.get("quantity")) * -1;
					//context.put("productId", order.get("product.id"));
					//context.put("updateAvailableQty", true);
					//context.put("quantity", qty);
					//app.appData.put("DA.eCom.UpdateWarehouseItemQty", context);

					//context.put("updateAvailableQty", false);
					//context.put("quantity", qty * -1);
					//app.appData.put("DA.eCom.UpdateWarehouseItemQty", context);
				}
				i.postIteration(context, ref orderItems);

				app.ruleMgr.execute("createStatusChangeHistory", salesOrder, getArticleIdByUniqueTitle("ecom_sysStatus_checkedOut"));
				context.RuleGroup.executeAsync("notifyObservers", null, "", new object[] { "ecomCheckoutComplete", salesOrder });
			}
			catch (Exception e)
			{
				throw new eComException("error executing checkOutOrder.", e);
			}

		}

		

		protected internal Swaf.BGuid.Guid getArticleIdByUniqueTitle(string uniqueTitle)
		{
			Swaf.BGuid.Guid id = null;
			FlexiMap m = new FlexiMap();
			m.put("uniqueTitle", uniqueTitle);
			m.put("companyId", ActiveCompanyId);
			m.put("treeName", "Articles");
			IBizObj obj = Swaf.Application.currentApp.appData.get("DA.Articles.GetArticleIdByUniqueTitle", m) as IBizObj;
			if (obj != null)
				id = (Swaf.BGuid.Guid)obj.get("id");
			else
				throw new eComException("Error executing Checkout. Order System Status cannot be found in the db.");
			return id;
		}
		public void processCheckedOutOrder(IApplication app, IRuleContext context, Swaf.BGuid.Guid orderId)
		{
			try
			{
				IResults rc = app.ruleMgr.execute("getSalesOrderDetails", orderId);
				if (rc.ExceptionInfo != null)
					throw new eComException("error executing getSalesOrderDetails in processCheckedOutOrder bizrule.", rc.ExceptionInfo);

				IBizObj eComOrder = rc.CallResults as IBizObj;

				//TODO:These types of checks are worthless.  Need to validate that a good payment has been made and a
				//good delivery is setup.  If not, it shouldnt throw an exception, it should set the state of the
				//sales order to failed and still complete the checkout

				//if( eComOrder.get("preferredDeliveryMethod") == null)
				//    throw new eComException("error executing processCheckedOut. Delivery Method is missing.");
				//if (eComOrder.get("paymentTerm") == null)
				//    throw new eComException("error executing processCheckedOut. Payment Term is missing.");
				
				if (eComOrder != null && eComOrder.get("items") != null)
				{
					app.appData.put("DA.eCom.AddSalesOrderDelivery", eComOrder);
					FlexiMap m = new FlexiMap();
					foreach (IBizObj orderItem in eComOrder.get("items") as IBizObjList)
					{
						m.put("productId", orderItem.get("productId"));
						m.put("updateAvailableQty", false);
						m.put("quantity", Convert.ToInt32(orderItem.get("quantity")) * -1);
						app.appData.put("DA.eCom.UpdateWarehouseItemQty", m);

						//TODO: Individual order items should be associated to a delivery method based on 
						//some other criteria.  This will be expanded later.
						//if (orderItem.get("deliveryInfo") == null)
						//    orderItem.put("deliveryInfo", eComOrder.get("preferredDeliveryMethod"));
						//app.appData.put("DA.eCom.UpdateSalesOrderItem", orderItem);
					}
					app.ruleMgr.execute("createStatusChangeHistory", eComOrder, ActiveCompany.get("settings.soProcessingCompleteArticleId"));
				}
			}
			catch (Exception e)
			{
				throw new eComException("error executing processCheckedOutOrder.", e);
			}
        }

        #region payment Terms
		public void updatePaymentTerm(IApplication app, IRuleContext context, Swaf.BGuid.Guid id)
        {
            try
            {
				FlexiMap m = new FlexiMap();
                m.put("id",id);
                app.appData.put("DA.eCom.UpdatePaymentTerm", m);
            }
            catch (Exception e)
            {
                throw new eComException("error executing updatePaymentTerm", e);
            }
        }

		public void deletePaymentTerm(IApplication app, IRuleContext context, Swaf.BGuid.Guid id)
        {
            try
            {
				FlexiMap m = new FlexiMap();
                m.put("id", id);
                app.appData.put("DA.eCom.DeletePaymentTerm", m);
            }
            catch (Exception e)
            {
                throw new eComException("error executing deletePaymentTerm", e);
            }
        }
		public IBizObj getPaymentTerm(IApplication app, IRuleContext context, Swaf.BGuid.Guid id)
        {
            try
            {
				FlexiMap m = new FlexiMap();
                m.put("id", id);
                IBizObjList lst = app.appData.get("DA.eCom.GetPaymentTerm", m) as IBizObjList;
                return lst.numElements > 0 ? lst[0] : lst.insertNew();
            }
            catch (Exception e)
            {
                throw new eComException("error executing getPaymentTerm", e);
            }
        }

		public IBizObjList getCompanyPaymentTerms(IApplication app, IRuleContext context, Swaf.BGuid.Guid companyId)
		{
			try
			{
				FlexiMap m = new FlexiMap();
				m.put("companyId", companyId);
				IBizObjList lst = app.appData.get("DA.eCom.GetCompanyPaymentTerms", m) as IBizObjList;
				return lst;
			}
			catch (Exception e)
			{
				throw new eComException("error executing getpaymentTerms", e);
			}
		}

		public IBizObjList getPaymentTerms(IApplication app, IRuleContext context, Swaf.BGuid.Guid prodId)
        {
            try
            {
				FlexiMap m = new FlexiMap();
                m.put("prodId", prodId);
                IBizObjList lst = app.appData.get("DA.eCom.GetPaymentTerms", m) as IBizObjList;
                return lst;
            }
            catch (Exception e)
            {
                throw new eComException("error executing getpaymentTerms", e);
            }
        }
        #endregion

        #region delivery methods
        public void updateDeliveryMethod(IApplication app, IRuleContext context, Swaf.BGuid.Guid id)
        {
            try
            {
				FlexiMap m = new FlexiMap();
                m.put("id", id);
                app.appData.put("DA.eCom.AddDeliveryMethods", m);
            }
            catch (Exception e)
            {
                throw new eComException("error executing addDeliveryMethod", e);
            }
        }

        public void deleteDeliveryMethod(IApplication app, IRuleContext context, Swaf.BGuid.Guid id)
        {
            try
            {
				FlexiMap m = new FlexiMap();
                m.put("id", id);
                app.appData.put("DA.eCom.DeleteDeliveryMethod", m);
            }
            catch (Exception e)
            {
                throw new eComException("error executing deleteDeliveryMethod", e);
            }
        }

        public IBizObj getDeliveryMethod(IApplication app, IRuleContext context, Swaf.BGuid.Guid id)
        {
            try
            {
				FlexiMap m = new FlexiMap();
                m.put("id", id);
                IBizObjList lst = app.appData.get("DA.eCom.GetDeliveryMethod", m) as IBizObjList;
                return lst.numElements > 0 ? lst[0] : lst.insertNew();
            }
            catch (Exception e)
            {
                throw new eComException("error executing getDeliveryMethod", e);
            }
        }

        public IBizObjList getDeliveryMethods(IApplication app, IRuleContext context)
        {
            try
            {
                IBizObjList lst = app.appData.get("DA.eCom.GetDeliveryMethods", context) as IBizObjList;
                return lst;
            }
            catch (Exception e)
            {
                throw new eComException("error executing getDeliveryMethod", e);
            }
        }
        #endregion

        #region Order Delivery
        public void updateOrderDelivery(IApplication app, IRuleContext context, IBizObj obj)
        {
            try
            {
                if (obj.isNew)
                    app.appData.put("DA.eCom.AddOrderDelivery", obj);
                else
                    app.appData.put("DA.eCom.UpdateOrderDelivery", obj);
            }
            catch (Exception e)
            {
                throw new eComException("error executing addOrderDelivery", e);
            }
        }
        public void deleteOrderDelivery(IApplication app, IRuleContext context, Swaf.BGuid.Guid id)
        {
            try
            {
				FlexiMap m = new FlexiMap();
                m.put("id", id);
                app.appData.put("DA.eCom.DeleteOrderDelivery", m);
            }
            catch (Exception e)
            {
                throw new eComException("error executing deleteOrderDelivery", e);
            }
        }

        public IBizObj getOrderDelivery(IApplication app, IRuleContext context, Swaf.BGuid.Guid id)
        {
            try
            {
				FlexiMap m = new FlexiMap();
                m.put("id", id);
                IBizObjList lst = app.appData.get("Da.eCom.GetOrderDelivery", m) as IBizObjList;
                return lst.numElements > 0 ? lst[0] : lst.insertNew();
            }
            catch (Exception e)
            {
                throw new eComException("error executing getOrderDelivery", e);
            }
        }
        #endregion
    }
	public enum ProductMetaType 
	{ 
		Simple,
		Bundled,
		WithChild
	}
	public enum ShippingBoxOption
	{
		NotShippable = 0,
		ShipWithOtherProducts = 1,
		ProductIsShippingBox = 2,
		CustomShippingBoxes = 3
	}
	public enum WizStepOptions { requiredBeforeCheckout = 0, optional = 1, mustCompleteBeforeMoveForward = 2 };
	public enum SalesOrderEditLevel { none, veryLimited, basic, full };
}
